/*
 * Copyright 2012 Marsrutai.lt
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package lt.marsrutai.mobile.android.fragment;

import java.util.List;

import lt.marsrutai.mobile.android.AppContext;
import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.activity.intent.FastestRouteDetailsIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.FastestRoutesResultIntentHolder;
import lt.marsrutai.mobile.android.adapter.RouteAdapter;
import lt.marsrutai.mobile.android.exception.DataAccessException;
import lt.marsrutai.mobile.android.manager.ActivityManager;
import lt.marsrutai.mobile.android.model.FastestRouteSearchBookmark;
import lt.marsrutai.mobile.android.model.Route;
import lt.marsrutai.mobile.android.model.RouteSearchResult;
import lt.marsrutai.mobile.android.model.RouteSearchStatus;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

import com.actionbarsherlock.app.SherlockListFragment;


public class RoutesFragment extends SherlockListFragment {

    private static final int START_STOP_CLARIFY_DIALOG_ID = 0;
    private static final int END_STOP_CLARIFY_DIALOG_ID = 1;

    private ActivityManager manager;

    private RouteSearchResult searchResult;
    private ArrayAdapter<Route> adapter;

    private String dateTime;
    private String stopFrom;
    private String stopTo;
    private String scope;
    private boolean isArrivalInd;
    private int maxRides;
    private int changeDuration;
    private int walkSpeed;
    private int maxWalkDistance;
    private String transports;

    private FastestRouteSearchBookmark bookmarkRepresentation;

    /** Indicates whether clarification for this particular stop was performed. Used only if clarification is needed. */
    private ClarificationStatus stopFromClarifyStatus;
    /** Indicates whether clarification for this particular stop was performed. Used only if clarification is needed. */
    private ClarificationStatus stopToClarifyStatus;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.list_fragment, null);
        TextView emptyText = (TextView) view.findViewById(android.R.id.empty);
        emptyText.setText(R.string.fastest_route_not_found);
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        manager = new ActivityManager(getActivity());
        
        receiveItemData(savedInstanceState);

        adapter = new RouteAdapter(getActivity(), scope);
        setListAdapter(adapter);
        
        if (searchResult == null) {
            downloadData();
        }
        else {
            displayResults();
        }
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        sendItemData(position);
    }
    
    @Override
    public void onSaveInstanceState(Bundle outState) {
        FastestRoutesResultIntentHolder intentHolder = new FastestRoutesResultIntentHolder(new Bundle());
        intentHolder.setScopeFolder(scope);
        intentHolder.setDateTime(dateTime);
        intentHolder.setStopFrom(stopFrom);
        intentHolder.setStopTo(stopTo);
        intentHolder.setIsArrivalInd(isArrivalInd);
        intentHolder.setSearchResult(searchResult);
        intentHolder.setStopFromClarifyStatus(stopFromClarifyStatus);
        intentHolder.setStopToClarifyStatus(stopToClarifyStatus);
        intentHolder.setMaxRides(maxRides);
        intentHolder.setChangeDuration(changeDuration);
        intentHolder.setWalkSpeed(walkSpeed);
        intentHolder.setMaxWalkDistance(maxWalkDistance);
        intentHolder.setTransports(transports);
        intentHolder.setBookmarkRepresentation(bookmarkRepresentation);
        
        outState.putAll(intentHolder.getIntent().getExtras());
        super.onSaveInstanceState(outState);
    }

    public void receiveItemData(Bundle bundle) {
        FastestRoutesResultIntentHolder intentHolder = new FastestRoutesResultIntentHolder(bundle != null ? bundle : getArguments());
        scope = intentHolder.getScopeFolder();
        dateTime = intentHolder.getDateTime();
        stopFrom = intentHolder.getStopFrom();
        stopTo = intentHolder.getStopTo();
        isArrivalInd = intentHolder.getIsArrivalInd();
        searchResult = intentHolder.getSearchResult();
        stopFromClarifyStatus = intentHolder.getStopFromClarifyStatus();
        stopToClarifyStatus = intentHolder.getStopToClarifyStatus();
        maxRides = intentHolder.getMaxRides();
        changeDuration = intentHolder.getChangeDuration();
        walkSpeed = intentHolder.getWalkSpeed();
        maxWalkDistance = intentHolder.getMaxWalkDistance();
        transports = intentHolder.getTransports();
        bookmarkRepresentation = intentHolder.getBookmarkRepresentation();
    }

    public void sendItemData(int i) {
        Route route = searchResult.getRoutes().get(i);
        FastestRouteDetailsIntentHolder intentHolder = new FastestRouteDetailsIntentHolder(getActivity());
        intentHolder.setSegments(route.getSegments());
        intentHolder.setScopeFolder(scope);
        startActivity(intentHolder.getIntent());
    }

    public void downloadData() {
        manager.showDownloadLoadingBar();
        Runnable downloadTask = new Runnable() {

            @Override
            public void run() {
                findRoutes(scope, stopFrom, stopTo, dateTime, isArrivalInd, maxRides, changeDuration, maxWalkDistance, walkSpeed, transports);
            }
        };
        Thread thread = new Thread(downloadTask);
        thread.start();
    }

    protected void findRoutes(String scope, String stopFrom, String stopTo, String dateTime, boolean isArrival, int maxRides, int changeDuration, int maxWalkDistance, int walkSpeed, String transports) {
        try {
            ConnectivityManager connManager = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo wifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

            boolean withPolyline = false;
            
            if (wifiInfo.isConnected()) {
                withPolyline = true;
            }
            
            searchResult = AppContext.getDataService().findRoutes(scope, stopFrom, stopTo, dateTime, isArrival, maxRides, changeDuration, maxWalkDistance, walkSpeed, transports, withPolyline);
        }
        catch (DataAccessException e) {
            manager.runOnUiThread(manager.errorRes);
            return;
        }
        manager.runOnUiThread(returnRes);
    }

    private Runnable returnRes = new Runnable() {

        @Override
        public void run() {
            displayResults();
        }
    };

    /**
     * Opens stop clarification dialogs if needed and downloads data when "from"
     * and "to" stop names are valid.
     */
    private void clarifyName() {
        // If any of the clarifications were cancelled, display an empty result screen
        if (stopFromClarifyStatus == ClarificationStatus.CANCELLED || stopToClarifyStatus == ClarificationStatus.CANCELLED) {
            manager.dismissDownloadLoadingBar();
        }
        // if result needs to be clarified, launch clarification dialog
        else if (searchResult.getStartStatus() == RouteSearchStatus.CLARIFY_NAME && stopFromClarifyStatus == null) {
            launchClarificationDialog(START_STOP_CLARIFY_DIALOG_ID, R.string.fastest_route_clarify_start_stop, searchResult.getStartChoices(), "StartStopClarificationDialogFragment");
            stopFromClarifyStatus = ClarificationStatus.STARTED;
        }
        // if result needs to be clarified, launch clarification dialog
        else if (searchResult.getEndStatus() == RouteSearchStatus.CLARIFY_NAME && stopToClarifyStatus == null) {
            launchClarificationDialog(END_STOP_CLARIFY_DIALOG_ID, R.string.fastest_route_clarify_end_stop, searchResult.getEndChoices(), "EndStopClarificationDialogFragment");
            stopToClarifyStatus = ClarificationStatus.STARTED;
        }
        // If stop names have been clarified or the result is OK perform data download anew
        else if ((searchResult.getStartStatus() == RouteSearchStatus.CLARIFY_NAME && stopFromClarifyStatus == ClarificationStatus.FINISHED || searchResult.getStartStatus() == RouteSearchStatus.OK) 
                && (searchResult.getEndStatus() == RouteSearchStatus.CLARIFY_NAME && stopToClarifyStatus == ClarificationStatus.FINISHED || searchResult.getEndStatus() == RouteSearchStatus.OK)) {
            downloadData();
        }
    }
    
    /**
     * Displays search results
     */
    protected void displayResults() {
        if (searchResult.getStartStatus() == RouteSearchStatus.OK && searchResult.getEndStatus() == RouteSearchStatus.OK) {
            List<Route> routes = searchResult.getRoutes();
            if (routes != null && routes.size() > 0) {
                for (int i = 0; i < routes.size(); i++) {
                    adapter.add(routes.get(i));
                }
            }
            manager.dismissDownloadLoadingBar();
        }
        // If at least one of the two names is not found, then return
        else if (searchResult.getStartStatus() == RouteSearchStatus.NAME_NOT_FOUND || searchResult.getEndStatus() == RouteSearchStatus.NAME_NOT_FOUND) {
            manager.dismissDownloadLoadingBar();
            return;
        }
        // otherwise perform name clarification
        else {
            clarifyName();
        }
    }

    protected void launchClarificationDialog(int id, int title, List<String> choices, String tag) {
        DialogFragment dialog = new StopClarificationDialogFragment();
        
        FastestRoutesResultIntentHolder holder = new FastestRoutesResultIntentHolder(getActivity());
        holder.setDialogTitle(title);
        holder.setDialogChoices(choices);
        holder.setDialogId(id);
        
        dialog.setArguments(holder.getIntent().getExtras());
        dialog.show(getActivity().getSupportFragmentManager(), tag);
    }

    public void onClarificationDialogItemSelected(int dialogId, String selectedItem) {
        switch (dialogId) {
        case START_STOP_CLARIFY_DIALOG_ID:
            stopFromClarifyStatus = ClarificationStatus.FINISHED;
            stopFrom = selectedItem;
            break;
        case END_STOP_CLARIFY_DIALOG_ID:
            stopToClarifyStatus = ClarificationStatus.FINISHED;
            stopTo = selectedItem;
            break;
        }
        clarifyName();
    }

    public void onClarificationDialogCancelled(int dialogId) {
        switch (dialogId) {
        case START_STOP_CLARIFY_DIALOG_ID:
            stopFromClarifyStatus = ClarificationStatus.CANCELLED;
            break;
        case END_STOP_CLARIFY_DIALOG_ID:
            stopToClarifyStatus = ClarificationStatus.CANCELLED;
            break;
        }
        clarifyName();
    }

    public FastestRouteSearchBookmark getBookmarkRepresentation() {
        return bookmarkRepresentation;
    }

    public static enum ClarificationStatus {
        
        STARTED, FINISHED, CANCELLED
    }
}
